package ru.susu.algebra.ranks;

import java.math.BigInteger;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * @author akargapolov
 * @since: 22.03.2011
 */
public class FullDPRanksTestBatchLoad
{
	private static Logger _log = Logger.getLogger("ranks");

	private static Connection _connection;

	private static int[] batch_sizes = new int[] { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000};

	public static void main(String[] args) throws Exception
	{
		BasicConfigurator.configure();

		ArrayList<String> list = Lists.newArrayList();
		Connection connection = getConnection();

		Date start = new Date();
		ResultSet rs = connection.prepareStatement("select key from tbl_data_new_new limit 100000").executeQuery();
		while (rs.next())
		{
			list.add(rs.getString(1));
		}
		rs.close();
		_log.info("load 100000 time - " + (new Date().getTime() - start.getTime()) + "ms");

		NumberFormat doubleFormat = new DecimalFormat();
		doubleFormat.setMaximumFractionDigits(5);

		int maxBatch = batch_sizes[batch_sizes.length - 1];
		Random rand = new Random();
		for (int batch : batch_sizes)
		{
			ArrayList<String> keys = Lists.newArrayList();
			for (int i = 0; i < maxBatch; i++)
				keys.add(list.get(rand.nextInt(list.size())));

			_connection = getConnection();

			start = new Date();

			for (int i = 0;i < maxBatch / batch;i++)
			{
				getData(Lists.newArrayList(keys.subList(i * batch, (i + 1) * batch)));
			}

			long time = (new Date().getTime() - start.getTime());
			_log.info("load batches " + batch + " time - " + time + "ms " + doubleFormat.format((((double)time) / maxBatch)) + " per line");
			_connection.close();
		}

		connection.close();
	}

	private static Connection getConnection() throws SQLException
	{
		try
		{
			Class.forName("org.postgresql.Driver");
			Connection connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/alternating_ranks",
					"postgres", "1234");
			connection.setAutoCommit(true);
			return connection;
		}
		catch (ClassNotFoundException e)
		{
			throw new SQLException(e);
		}
	}

	private static Map<Integer, String> _queries = Maps.newHashMap();

	static
	{
		for (int batch : batch_sizes)
		{
			StringBuilder builder = new StringBuilder();
			for (int index = 0; index < batch; index++)
			{
				builder.append((index == 0) ? "" : ", ");
				builder.append("?");
			}
			_queries.put(batch, "SELECT key, bvalue FROM tbl_data_new_new where key in (" + builder.toString() + ")");
		}
	}

	protected static Map<String, BigInteger> getData(List<String> keys) throws Exception
	{
		Map<String, BigInteger> result = Maps.newHashMap();

		PreparedStatement psmt = _connection.prepareStatement(_queries.get(keys.size()));
		for (int index = 0; index < keys.size(); index++)
		{
			psmt.setString(index + 1, keys.get(index));
			// psmt.setArray(1, x);
		}
		ResultSet rs = psmt.executeQuery();
		while (rs.next())
		{
			String key = rs.getString(1);
			BigInteger value = new BigInteger(rs.getString(2));
			result.put(key, value);
		}
		rs.close();
		psmt.close();
		return result;
	}

	protected static int getIndex(int i, int k, int shift)
	{
		return i * 10000 * 10 + k * 10 + shift;
	}

	private static String DELIMITER = "_";

	protected static String getKey(int i, int k, int shift, BitSet bitset)
	{
		return new StringBuilder().append(i).append(DELIMITER).append(k).append(DELIMITER).append(shift).append(
				DELIMITER).append(bitset).toString();
	}
}
